import { CacheModule } from '@nestjs/cache-manager';
import { Inject, Module, OnApplicationBootstrap } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { APP_INTERCEPTOR } from '@nestjs/core';
import * as chalk from 'chalk';
import * as dayjs from 'dayjs';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import * as DailyRotateFile from 'winston-daily-rotate-file';

import { ApiModule } from './api/api.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import configuration from './config/configuration';
import { GlobalModule } from './core/common/global/dataFactory/dataFactory.module';
import { ResponseFormatterInterceptor } from './core/common/interceptors/globResFormatter.interceptor';
import { ScheduleModule } from './schedule/schedule.module';
import { ScheduleService } from './schedule/schedule.service';

@Module({
  imports: [
    /** 缓存 */
    CacheModule.register({ isGlobal: true }),

    /** 公共配置 */
    ConfigModule.forRoot({ isGlobal: true, load: [configuration] }),

    /** 全局模块 */
    GlobalModule,

    /** 日志模块 */
    WinstonModule.forRoot({
      exitOnError: false, // 防止意外退出

      transports: [
        /** 控制台输出 */
        new winston.transports.Console({
          level: 'verbose',
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.colorize(),
            winston.format.printf(params => {
              const { context, level, timestamp, message } = params;

              const time = dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss');

              return `${chalk.yellow(time)} ${level}: [${context}] ${message}`;
            }),
          ),
        }),

        /** 日志文件 */
        new DailyRotateFile({
          dirname: 'log/silly',
          filename: '%DATE%.log',
          datePattern: 'YYYY-MM-DD',
          level: 'silly',
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.printf(params => {
              const { context, level, timestamp, message } = params;
              const time = dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss');
              return `${time} ${level}: [${context}] ${message}`;
            }),
          ),
        }),
      ],

      exceptionHandlers: [
        new winston.transports.DailyRotateFile({
          filename: '%DATE%.log',
          dirname: 'log/error',
          datePattern: 'YYYY-MM-DD',
        }),
      ],

      rejectionHandlers: [
        new winston.transports.DailyRotateFile({
          filename: '%DATE%.log',
          dirname: 'log/error',
          datePattern: 'YYYY-MM-DD',
        }),
      ],
    }),

    /** 任务分发模块 */
    ScheduleModule,

    ApiModule,
  ],
  controllers: [AppController],

  providers: [
    AppService,

    /** 全局拦截器 */
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseFormatterInterceptor,
    },
  ],
})
export class AppModule implements OnApplicationBootstrap {
  @Inject()
  private scheduleService: ScheduleService;

  onApplicationBootstrap() {
    setImmediate(() => this.scheduleService.run());
  }
}
